package com.dp.mallchat.common.user.service.impl;

import cn.hutool.extra.spring.SpringUtil;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.dp.mallchat.common.chat.domain.entity.RoomFriend;
import com.dp.mallchat.common.chat.service.ChatService;
import com.dp.mallchat.common.chat.service.MessageService;
import com.dp.mallchat.common.chat.service.RoomService;
import com.dp.mallchat.common.chat.service.adapter.MessageAdapter;
import com.dp.mallchat.common.common.annotation.MyRedissonLock;
import com.dp.mallchat.common.common.domain.vo.req.PageBaseReq;
import com.dp.mallchat.common.common.domain.vo.resp.PageBaseResp;
import com.dp.mallchat.common.common.event.FriendEvent;
import com.dp.mallchat.common.common.utils.AssertUtil;
import com.dp.mallchat.common.user.dao.UserApplyDao;
import com.dp.mallchat.common.user.domain.entity.UserApply;
import com.dp.mallchat.common.user.domain.entity.UserFriend;
import com.dp.mallchat.common.user.domain.user.enums.UserApplyEnum;
import com.dp.mallchat.common.user.domain.user.enums.UserApplyReadStatusEnum;
import com.dp.mallchat.common.user.domain.user.enums.UserApprovalStatusEnum;
import com.dp.mallchat.common.user.domain.user.req.FriendApplyReq;
import com.dp.mallchat.common.user.domain.user.resp.FriendCheckResp;
import com.dp.mallchat.common.user.domain.user.resp.FriendUnreadResp;
import com.dp.mallchat.common.user.domain.user.resp.UserApplyPageResp;
import com.dp.mallchat.common.user.mapper.UserApplyMapper;
import com.dp.mallchat.common.user.service.UserApplyService;
import com.dp.mallchat.common.user.service.UserFriendService;
import com.dp.mallchat.common.user.service.adapter.UserApplyAdapter;
import com.dp.mallchat.common.user.service.adapter.UserFriendAdapter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @Author: dupeng
 * @CreateTime: 2024-06-19  18:15
 * @Description:
 */
@Service
@Slf4j
public class UserApplyServiceImpl extends ServiceImpl<UserApplyMapper, UserApply> implements UserApplyService {

    @Autowired
    private UserApplyDao userApplyDao;
    @Autowired
    private UserFriendService userFriendService;
    @Autowired
    private RoomService roomService;
    @Autowired
    private MessageService messageService;
    @Autowired
    private ApplicationEventPublisher applicationEventPublisher;


    @Override
    public PageBaseResp<UserApplyPageResp> pageApply(Long uid, PageBaseReq pageBaseReq) {
        Page<UserApply> userApplyList = userApplyDao.listByUid(uid, pageBaseReq.plusPage());
        if (CollectionUtils.isEmpty(userApplyList.getRecords())) {
            return PageBaseResp.empty();
        }
        //将申请好有消息变更为已读
        List<Long> ids = userApplyList.getRecords().stream().filter(item -> UserApplyReadStatusEnum.UN_READ.getType().equals(item.getReadStatus())).map(UserApply::getId).collect(Collectors.toList());
        if (!CollectionUtils.isEmpty(ids)) {
            userApplyDao.updateReadStatus(ids);
        }
        //返回
        return PageBaseResp.init(userApplyList, UserApplyAdapter.buildUserApplyList(userApplyList.getRecords()));
    }


    @Override
    public FriendUnreadResp unread(Long uid) {
        Integer count = userApplyDao.countUnRead(uid);
        return UserFriendAdapter.buildUnreadResp(count);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void apply(Long uid, FriendApplyReq req) {
        // 判断是否是好友
        UserFriend userFriend = userFriendService.isUserFriend(uid, req.getTargetUid());
        AssertUtil.isEmpty(userFriend, "已经是好友喔~");

        // 判断是否已经申请过(自己的)
        UserApply userApply = userApplyDao.selectById(uid, req.getTargetUid(), UserApplyEnum.ADD_FRIEND.getType(), UserApprovalStatusEnum.UN_PASS.getStatus());
        if (Objects.nonNull(userApply)) {   //存在记录，申请过了
            log.info("已有好友申请记录,uid:{}, targetId:{}", uid, req.getTargetUid());
            return;
        }

        // 判断对方是否发起过申请(别人请求自己的)
        UserApply targetUserApply = userApplyDao.selectById(req.getTargetUid(), uid, UserApplyEnum.ADD_FRIEND.getType(), UserApprovalStatusEnum.UN_PASS.getStatus());
        if (Objects.nonNull(targetUserApply)) {
            //审批事件
            SpringUtil.getBean(UserApplyService.class).applyApproval(uid, targetUserApply.getUid());
            return;
        }

        // 添加申请记录
        UserApply insert = UserFriendAdapter.buildUserApply(uid, req);
        save(insert);

        //申请事件  被请求人接收申请通知
        applicationEventPublisher.publishEvent(new FriendEvent(this, insert));
    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    @MyRedissonLock(key = "#uid")
    public void applyApproval(Long uid, Long applyId) {
        UserApply userApply = userApplyDao.getById(applyId);
        AssertUtil.isNotEmpty(userApply, "申请记录不存在~！");
        AssertUtil.equal(uid, userApply.getTargetId(),"不存在申请记录~！");
        AssertUtil.equal(UserApprovalStatusEnum.UN_PASS.getStatus(), userApply.getStatus(),"申请记录已处理~！");

        // 更新状态为同意
        userApplyDao.agree(applyId);
        // 创建好友关系
        userFriendService.createFriend(userApply.getTargetId(), userApply.getUid());
        //创建一个聊天房间
        RoomFriend roomFriend = roomService.createFriendRoom(Arrays.asList(uid, userApply.getUid()));
        //发送一条同意消息。。我们已经是好友了，开始聊天吧
        messageService.sendMessage(uid, MessageAdapter.buildAgreeMsg(roomFriend.getRoomId()));
    }

    @Override
    public FriendCheckResp check(Long uid, List<Long> uidList) {
        List<UserFriend> userFriendList = userFriendService.isUserFriend(uid, uidList);

        Set<Long> friendUidList = userFriendList.stream().map(UserFriend::getFriendUid).collect(Collectors.toSet());

        List<FriendCheckResp.FriendCheck> friendCheckList = uidList.stream().map(friendUid -> {
            FriendCheckResp.FriendCheck friendCheck = new FriendCheckResp.FriendCheck();
            friendCheck.setUid(friendUid);
            friendCheck.setIsFriend(friendUidList.contains(friendUid));
            return friendCheck;
        }).collect(Collectors.toList());

        return new FriendCheckResp(friendCheckList);
    }

}
